package org.dei.test.llqruntime.stack;

import org.dei.perla.parser.expressions.*;
import org.dei.perla.parser.statements.*;
import org.dei.perla.sys.device.fpc.*;
import org.dei.perla.sys.llqruntime.*;
import org.dei.perla.sys.llqruntime.datastructures.*;
import org.dei.perla.utils.pipe.*;
import org.dei.perla.utils.waiter.*;

/**
 * Questa classe rappresenta l'oggetto incaricato del recupero dei dati campionati da parte
 * dell'<tt>FPC</tt>.
 *
 */
public class DataCollectorNew extends Thread{
		

	private LLDataCollectionInfo pInfo;
	private FPC pFPC;
	private Buffer pBuffer;
	private SamplingFrequenciesTable pTable;
	private Waiter<Pipe<Record>> pRecordWaiter;
	private Node pWhereNode;
	

	/**
	 * Costruisce un nuovo oggetto del tipo DataCollector
	 * @param parInfo le informazioni di cui ha bisogno il DataCollector
	 */
	public DataCollectorNew(LLDataCollectionInfo parInfo) {
		
		this.pInfo = parInfo;
		this.pBuffer = parInfo.getLocalBuffer();
		this.pFPC = parInfo.getAssociatedFPC();
		this.pTable = parInfo.getTable();
		this.pWhereNode = parInfo.getWhereCondition();
		pRecordWaiter = new Waiter<Pipe<Record>>();
		pRecordWaiter.start();
		pRecordWaiter.addWaitable(((FPCmockup) pFPC).getPipe((LLStatement) parInfo.getRepresentedStatement()).getWaitable());
	}
	
	/**
	 * @return Le informazioni di basso livello associate a questo DataCollector
	 */
	public LLDataCollectionInfo getLLDataCollectionInfo() {
		return this.pInfo;
	}
	
	/**
	 * Mette in esecuzione il DataCollector
	 */
	public void run() { 
		
		Record tRecord;
		System.out.println("*** DATA COLLECTOR starts ***");
		Waitable<Pipe<Record>> tTmpWaitable;
		Pipe<Record> tTmpPipe;
		
		do {
			tTmpWaitable = pRecordWaiter.waitNext();
			tTmpPipe = tTmpWaitable.getParentComponent();
			tRecord = tTmpPipe.dequeue();
			
			if(tRecord == null) {
				System.out.println("PIPE CHIUSA");
				tTmpPipe.stop();
				pRecordWaiter.stop();
				tRecord = null;
				break;
			}
			
			System.out.println("Record letto da "+pFPC.getName());
			
			if (performWhere(tRecord))
			{
				//...i record che si "salvano" dopo la performWhere() vengono inseriti nell'LocBuf
				
				pBuffer.addRecord(tRecord);
				System.out.println("Record aggiunto dal DC collegato a "+pFPC.getName());
				System.out.println("["+pBuffer.getBuffer().size()+"]"+"<---Il record ora nel buffer contiene il valore: \n" + tRecord);
			}	
			else
			{
				System.out.println("*** Record SCARTATO dalla WHERE***");
			}

			if (pTable!=null) {
				
				if (setFrequencyValue(pTable,tRecord)) {
					System.out.println("*** Frequenza AGGIORNATA ***");
				} else {
					System.out.println("*** "+pFPC.getName()+" ha segnalato errore nella frequenza ***");
				}
				
				//TODO nel caso di errore bisogna vedere se siamo in DO_NOT_SAMPLE... perchè DC in questo
				//	   caso avrebbe finito il suo lavoro.	
			
			}
			
			
		} while (true);
		
		System.out.println("*** DATA COLLECTOR ha terminato ***");
		
		
	}
	
	/**
	 * Metodo helper: data una tabella e un record aggiorna la frequenza di campionamento sull'FPC
	 * @param parTable la tabella
	 * @param parRecord il record
	 * @return TRUE se ok, FALSE altrimenti
	 */
	private boolean setFrequencyValue(SamplingFrequenciesTable parTable, Record parRecord) {
		
		boolean bValue = true;
		
		for (FrequencyRecord tFreqRec : parTable.getTableContent()) {
			
			if (ExpressionEvaluator.evaluate(parRecord,tFreqRec.getFirstOperand())) {
				
				bValue = ((FPCmockup) pFPC).setMockupSamplingTime((long)tFreqRec.getFrequency().getValue()*1000,null,(LLStatement) pInfo.getRepresentedStatement());
				//bValue = (pFPC.setSamplingTime((long)tFreqRec.getFrequency().getValue()*1000, parTable.getBehaviour(),pInfo.getRepresentedStatement()));
				if (bValue == true) break;
			}
			
		}
		return bValue;
	}
	/**
	 * Metodo helper per la valutazione della clausola Where
	 * @param parRecord il record su cui controllare la clausola WHERE
	 * @return TRUE se il record è accettabile, FALSE se va' scartato
	 */
	private boolean performWhere(Record parRecord) {
		
		return ExpressionEvaluator.evaluate(parRecord,pWhereNode);
	}
}